<script>
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import { createObjectURL } from 'pdfjs-dist'
export default {
  components: {
    'ImageViewer': ElImageViewer
  },
  emits: ['delete'],
  props: {
    value: {
      required: true,
      default() {
        return null
      }
    },
    tips: {
      type: String,
      default: '上传图片'
    },
    handleUpload: {
      type: Function,
      default: null
    },
    handleDelete: {
      type: Function,
      default: (callback) => {
        callback()
      }
    },
    disabled: {
      type: Boolean,
      default() {
        return false
      }
    }
  },
  data() {
    return {
      imageViewer: {
        visible: false,
        zIndex: 999,
        initialIndex: 0,
        urlList: []
      },
      localURL: null,
      progress: 0,

      // empty(无图状态) uploading(上传中) ready(上传成功) fail(上传失败)
      state: typeof this.value === 'string' ? 'ready' : 'empty'
    }
  },
  computed: {
    url: {
      get() {
        return this.value
      },
      set(url) {
        this.$emit('input', url)
      }
    }
  },
  watch: {
    url(url) {
      if (typeof url === 'string' && url.trim() !== '') {
        this.state = 'ready'
      } else {
        this.state = 'empty'
      }
    }
  },
  methods: {
    closeImageViewer() {
      this.imageViewer.visible = false
    },
    openImageViewer(url) {
      this.imageViewer.urlList = [url]
      this.imageViewer.visible = true
    },
    onFileSelectorChange(e) {
      if (e.target.files.length <= 0) { return }

      const files = [...e.target.files]
      this.clearFileSelector()
            this.handleUpload?.(this.buildTask(files[0]))
    },
    buildTask(file) {
      this.localURL = createObjectURL(file)

      const onStart = () => {
        this.state = 'uploading'
        this.progress = 0
      }

      const onChange = (progress) => {
        this.progress = progress
      }

      const onSuccess = (url) => {
        this.state = 'ready'
        this.url = url
        this.progress = 100
      }

      const onFailed = () => {
        this.progress = 0
        this.state = 'fail'
      }

      return {
        file,
        handlers: {
          onStart,
          onChange,
          onSuccess,
          onFailed
        }
      }
    },
    clearFileSelector() {
      this.$refs.fileSelector.value = null
    },
    openImageSelector() {
      if (this.disabled) return
            this.$refs.fileSelector?.dispatchEvent(new MouseEvent('click'))
    },
    handleDeleteFn() {
      if (this.disabled) return
      this.url = null
      this.state = 'empty'
    },

    // ----------
    isStateReady(state) {
      return state === 'ready'
    },
    isStateFail(state) {
      return state === 'fail'
    },
    isStateUploading(state) {
      return state === 'uploading'
    },
    isStateEmpty(state) {
      return state === 'empty'
    }
  }
}
</script>

<template>
  <div class="image-with-upload__container">
    <div v-if="isStateReady(state)" class="cover-container" @click="openImageViewer(url)">
      <img class="cover" :src="url">
      <div
        v-if="!disabled"
        class="cover-delete-btn"
        @click.stop="handleDelete(handleDeleteFn)"
      >
        <i class="el-icon-close" />
      </div>
    </div>

    <div v-else-if="isStateUploading(state)" class="cover-container" @click="openImageViewer(url)">
      <img class="cover" :src="localURL">
      <div class="uploading-cover stateful">
        <i class="icon el-icon-loading" />
        <span class="text">{{ progress }}%</span>
      </div>
    </div>

    <div v-else-if="isStateFail(state)" class="cover-container" @click="openImageViewer(url)">
      <img class="cover" :src="localURL">
      <div class="fail-cover stateful">
        <i class="icon el-icon-warning-outline" />
        <span class="text">上传失败</span>
      </div>
      <div
        class="cover-delete-btn"
        @click.stop="handleDelete(handleDeleteFn)"
      >
        <i class="el-icon-close" />
      </div>
    </div>

    <div v-else-if="isStateEmpty(state)" class="upload-btn stateful" @click="openImageSelector">
      <i class="icon el-icon-camera" />
      <span class="text">{{ tips }}</span>
    </div>

    <ImageViewer
      v-if="imageViewer.visible"
      :z-index="imageViewer.zIndex"
      :initial-index="imageViewer.initialIndex"
      :on-close="closeImageViewer"
      :url-list="imageViewer.urlList"
    />

    <input
      ref="fileSelector"
      accept="image/*"
      type="file"
      style="display: none;"
      @change="onFileSelectorChange"
    >
  </div>
</template>

<style lang="scss">
.image-with-upload__container {
    overflow: hidden;
    position: relative;
    background-color: #f0f0f0;
    border: 1px solid #c0ccda;
    cursor: pointer;

    .cover-container {
        height: 100%;
        width: 100%;
        position: relative;

        .cover {
            height: 100%;
            width: 100%;
            object-fit: cover;
        }

        .uploading-cover {
            color: white;
            background-color: rgba(0,0,0,0.5);
        }

        .fail-cover {
            border: 1px dashed red;
            color: red;
            background-color: rgba(0,0,0,0.5);
            height: 100%;
            width: 100%;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 9000;
        }

        .cover-delete-btn {
            line-height: 1rem;
            background-color: #0000006b;
            color: white;
            position: absolute;
            font-size: 18px;
            top: 2px;
            right: 2px;
            border-radius: 2px;
            z-index: 10;
            cursor: pointer;
        }
    }

    .stateful {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: center;
        justify-content: center;
        // color: white;
        // background-color: rgba(0,0,0,0.25);
        font-size: 18px;
        cursor: pointer;

        .icon {
            font-size: 22px;
        }
        .text {
            font-size: 10px;
            line-height: 24px;
        }
    }

    .upload-btn {
        color: #8e8e8e;
    }
}
</style>
